#pragma once

#include "Shared/Interfaces/IKeyManager.h"
#include "Shared/KeyDefinitions.h"
#include "Utilities/AutoResetEvent.h"
#ifdef _WIN32
#include "Windows/XInputManager.h"
#else
#include "Linux/LinuxGameController.h"
#endif

#include <QObject>

class QWidget;
class Emulator;

class QKeyManager : public QObject, public IKeyManager
{
public:
    QKeyManager(Emulator *emu, QWidget *parent = nullptr);
    ~QKeyManager();

    void RefreshState() override;
    void UpdateDevices() override;
    bool IsMouseButtonPressed(MouseButton button) override;
    bool IsKeyPressed(uint16_t keyCode) override;
    optional<int16_t> GetAxisPosition(uint16_t keyCode) override;
    vector<uint16_t> GetPressedKeys() override;
    string GetKeyName(uint16_t keyCode) override;
    uint16_t GetKeyCode(string keyName) override;
    bool SetKeyState(uint16_t scanCode, bool state) override;
    void ResetKeyState() override;
    void SetDisabled(bool disabled) override;
    void SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft) override;

private:
    Emulator *m_emulator = nullptr;
#ifdef _WIN32
    unique_ptr<XInputManager> m_xInput;
#else
    std::vector<shared_ptr<LinuxGameController>> m_controllers;
#endif
    QWidget *m_widget = nullptr;

    std::thread m_updateDeviceThread;
    atomic<bool> m_stopUpdateDeviceThread;
    AutoResetEvent m_stopSignal;
    bool m_disableAllKeys = false;
    bool m_keyState[0x205] = {false};
    vector<KeyDefinition> m_keyDefinitions;
    unordered_map<uint16_t, string> m_keyNames;
    unordered_map<string, uint16_t> m_keyCodes;
    unordered_map<uint16_t, bool> m_keyPressedState;

    bool InitializeKeyDefinitions();
    void StartUpdateDeviceThread();
#ifndef _WIN32
    void CheckForGamepads(bool logInformation);
#endif
    bool eventFilter(QObject *obj, QEvent *event) override;
};
